#!/usr/bin/python3
# coding=utf-8

import io
import urllib
import urllib.error
import urllib.request
import json
import os
import rarfile
import hashlib
import threading
import copy
import time
import zipfile
import random
import platform
import PIL
from PIL import Image
from PIL import ImageTk
# import imageTk
import tkinter as tk
from tkinter.filedialog import *
from tkinter.simpledialog import *
from tkinter.messagebox import *
from tkinter.font import *
from tkinter import ttk
from tkinter import colorchooser
import ImgDiskManager
from ProxyData import *

_NONE = ""

BACK_IMG = 1
NEXT_IMG = 2
JUMP_IMG = 3

SLIDE_TIME = 3

BACK_FILE = -1
NEXT_FILE = 0
CURRENT_FILE = 1
NOCHANGE_FILE = 2
JUMP_FILE = 3
CHANGE_FILE = 4

BAD_FILE = "bad_file"

RANDOM_JUMP_IMG = False
RANDOM_LIST = [n for n in range(99999)]
random.shuffle(RANDOM_LIST)
RANDOM_LIST_LENGTH = 99999
RANDOM_LIST_INDEX = 0

CPS_CLASS = 0
FILE_CLASS = 1

IMG_NAME_MESSAGE = 0
IMG_NUM_MESSAGE = 1
FILE_NUM_MESSAGE = 2
FILE_NAME_MESSAGE = 3

MESSAGE_BAR_HEIGHT = 20
MESSAGE_BAR_INFO_WIDTH = 0.15
MESSAGE_BAR_IMG_NAME_WIDTH = 0.35
MESSAGE_BAR_IMG_NUM_WIDTH = 0.1
MESSAGE_BAR_FILE_NUM_WIDTH = 0.1
MESSAGE_BAR_FILE_NAME_WIDTH = 0.3

MANAGE_BAR_BUTTON_WIDTH = 20
MANAGE_BAR_LIST_WIDTH = 200

USE_FAVORITE_LIST = 1
USE_FILE_LIST = 2
USE_BOOKMARK_LIST = 3

NONE = 0
NEAREST = 0
ANTIALIAS = 1
LINEAR = 2
CUBIC = 3

SCALE_FIT_MODE_BOTH = 0
SCALE_FIT_MODE_WIDTH = 1
SCALE_FIT_MODE_HEIGHT = 2

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
SCREEN_SIZE_CHANGE = False

RIGHT_MENU_VISIBLE = False

PLATFORM = platform.system()

class _KeyCode():
    def __init__(self):
        self.codeA = 38
        self.codeS = 39
        self.codeD = 40
        self.codeW = 25
        self.codeE = 26
        self.codeR = 27
        self.codeC = 54
        self.codeLeft = 113
        self.codeRight = 114
        self.codeUp = 111
        self.codeDown = 116
        self.codeO = 32
        self.codeP = 33
        self.codeM = 58
        self.codeN = 57
        self.codeB = 56

class _configData():
    def __init__(self, background='#d3d3d3',
                 customBackground='#d3d3d3',
                 restore=True,
                 restoreData={'pageKey':'', 'subPageIndex':'', 'subPageName': 0, 'imgPos': 0},
                 slideTime=3,
                 scaleMode=NEAREST,
                 twoPageMode=False,
                 scaleFitMode=0,
                 mangaMode=False):
        self.background = background
        self.customBackground = customBackground
        self.restore = restore
        self.restoreData = restoreData
        self.slideTime = slideTime
        self.scaleMode = scaleMode
        self.twoPageMode = twoPageMode
        self.scaleFitMode = scaleFitMode
        self.mangaMode = mangaMode

    def getDataDict(self):
        return {'background': self.background,
                'customBackground': self.customBackground,
                'restore': self.restore,
                'restoreData': self.restoreData,
                'slideTime': self.slideTime,
                'scaleMode': self.scaleMode,
                'twoPageMode': self.twoPageMode,
                'scaleFitMode': self.scaleFitMode,
                'mangaMode': self.mangaMode}

    def setDataFromDict(self, dict):
        self.background = dict['background']
        self.customBackground = dict['customBackground']
        self.restore = dict['restore']
        self.restoreData = dict['restoreData']
        self.slideTime = dict['slideTime']
        self.scaleMode = dict['scaleMode']
        self.twoPageMode = dict['twoPageMode']
        self.scaleFitMode = dict['scaleFitMode']
        self.mangaMode = dict['mangaMode']

class configDialog():
    def __init__(self, master, command=None, oldConfig=None):
        self.scaleModeList = ['最近邻插值',
                              '抗锯齿',
                              '双线性插值',
                              '立方插值']
        self.command = command
        self.configData = oldConfig
        self.ft = Font(family='Fixdsys', size=10)
        self.configRoot = Toplevel(master)
        self.configRoot.wm_attributes('-topmost', 0.5)
        self.configRoot.wm_resizable(width=False, height=False)
        s_x = master.winfo_x()
        s_y = master.winfo_y()
        t = master.winfo_geometry()
        win_w = int(t.split('x')[0])
        win_h = int(t.split('x')[1].split('+')[0])
        self.configRoot.geometry("500x320+%d+%d" % ((win_w - 500) / 2 + s_x, (win_h - 450) / 2 + s_y))

        self.initBackgroundChoice(self.configRoot)
        self.initFile(self.configRoot)
        self.initOther(self.configRoot)

        self.configRoot.cancelButton = Button(self.configRoot, text='取消', command=self.clickCancel)
        self.configRoot.cancelButton.place(x=305, y=280, width=70, height=30)
        self.configRoot.cancelButton = Button(self.configRoot, text='确认', command=self.clickOk)
        self.configRoot.cancelButton.place(x=395, y=280, width=70, height=30)

        self.configRoot.mainloop()

    def clickCancel(self):
        if callable(self.command):
            self.command(None)
        self.configRoot.destroy()

    def clickOk(self):
        t_b = self.backIntV.get()
        if t_b == 0:
            self.configData.background = '#d3d3d3'
        elif t_b == 1:
            self.configData.background = '#000000'
        elif t_b == 2:
            self.configData.background = self.customBackground
        self.configData.customBackground = self.customBackground
        self.configData.restore = bool(self.restore.get())
        self.configData.slideTime = self.slideTime.get()
        self.configData.scaleMode = self.scaleModeList.index(self.scaleMode.get())
        if callable(self.command):
            self.command(self.configData)
        self.configRoot.destroy()

    def initBackgroundChoice(self, master):
        master.backgroundFrame = LabelFrame(master, text='背景', font=self.ft)
        master.backgroundFrame.place(x=20, y=10, width=220, height=150, anchor=NW)
        self.backIntV = IntVar()
        if self.configData.background == '#d3d3d3':
            self.backIntV.set(0)
            self.customBackground = '#ffffff'
        elif self.configData.background == '#000000':
            self.backIntV.set(1)
            self.customBackground = '#ffffff'
        else:
            self.customBackground = self.configData.background
            self.backIntV.set(2)

        master.backgroundFrame.lightRadioButton = Radiobutton(master.backgroundFrame,
                                                              text='使用灰色背景',
                                                              font=self.ft,
                                                              variable=self.backIntV,
                                                              value=0)
        master.backgroundFrame.lightRadioButton.grid(columnspan=2, sticky=NW)
        master.backgroundFrame.blackRadioButton = Radiobutton(master.backgroundFrame,
                                                              text='使用黑色背景',
                                                              font=self.ft,
                                                              variable=self.backIntV,
                                                              value=1)
        master.backgroundFrame.blackRadioButton.grid(row=1, columnspan=2, sticky=NW)
        master.backgroundFrame.customRadioButton = Radiobutton(master.backgroundFrame,
                                                               text='使用自定义颜色',
                                                               font=self.ft,
                                                               variable=self.backIntV,
                                                               value=2)
        master.backgroundFrame.customRadioButton.grid(row=2, sticky=NW, pady=4)
        master.backgroundFrame.colorChoiceButton = Button(master.backgroundFrame,
                                                          width=6,
                                                          command=self.choiceColor)
        master.backgroundFrame.colorChoiceButton.grid(row=2, column=1, sticky=NW, padx=10)
        master.backgroundFrame.colorChoiceButton.colorLabel = Label(master.backgroundFrame.colorChoiceButton,
                                                                    bg=self.customBackground)
        master.backgroundFrame.colorChoiceButton.colorLabel.place(x=-1,
                                                                  y=-1,
                                                                  relx=0.5,
                                                                  rely=0.5,
                                                                  anchor=CENTER,
                                                                  relheight=0.8,
                                                                  relwidth=0.8)
        master.backgroundFrame.colorChoiceButton.colorLabel.bind('<Button-1>', self.choiceColor)

    def choiceColor(self, *args):
        self.configRoot.wm_attributes('-topmost', 0)
        color_w = colorchooser.Chooser(master=self.configRoot,initialcolor=self.configData.background)
        c = color_w.show()[1]
        self.configRoot.backgroundFrame.colorChoiceButton.colorLabel['bg'] = c
        self.customBackground = c
        self.configRoot.wm_attributes('-topmost', 0.5)

    def initFile(self, master):
        master.fileFrame = LabelFrame(master, text='文件', font=self.ft)
        master.fileFrame.place(x=260, y=10, width=220, height=150, anchor=NW)

        self.restore = IntVar()
        self.restore.set(self.configData.restore)
        master.fileFrame.restoreCheckButton = Checkbutton(master.fileFrame,
                                                                text='启动时恢复上次浏览',
                                                                font=self.ft,
                                                                variable=self.restore)
        master.fileFrame.restoreCheckButton.grid(sticky=NW)

    def inputDepth(self, *args):
        try:
            depth = int(self.scanSubFileDepth.get())
            if depth > 99:
                raise Exception
            elif depth < -1:
                raise Exception
            self.configData.scanSubFileDepth = depth
        except:
            self.scanSubFileDepth.set(self.configData.scanSubFileDepth)

    def initOther(self, master):
        master.otherFrame = LabelFrame(master, text='杂项', font=self.ft)
        master.otherFrame.place(x=20, y=170, width=460, height=100, anchor=NW)

        master.otherFrame.slideTimeLabel = Label(master.otherFrame,
                                                 text='幻灯片延时',
                                                 font=self.ft)
        master.otherFrame.slideTimeLabel.place(relx=0.45, rely=0, anchor=NW)
        self.slideTime = IntVar()
        self.slideTime.set(self.configData.slideTime)
        master.otherFrame.slideTimeSpinbox = Spinbox(master.otherFrame,
                                                     from_=1,
                                                     to=20,
                                                     increment=1,
                                                     textvariable=self.slideTime)
        master.otherFrame.slideTimeSpinbox.place(relx=0.67, rely=0, relwidth=0.3, anchor=NW)
        master.otherFrame.slideTimeSpinbox.bind('<Return>', self.inputSlide)

        master.otherFrame.scaleModeLabel = Label(master.otherFrame,
                                                 text='图像放大方式',
                                                 font=self.ft)
        master.otherFrame.scaleModeLabel.place(relx=0.45, rely=0.4, anchor=NW)
        self.scaleMode = StringVar()
        self.scaleMode.set(self.scaleModeList[self.configData.scaleMode])
        master.otherFrame.scaleModeCombo = ttk.Combobox(master.otherFrame, textvariable=self.scaleMode, values=self.scaleModeList)
        master.otherFrame.scaleModeCombo.place(relx=0.668, rely=0.38, relwidth=0.301, relheight=0.35, anchor=NW)

    def inputSlide(self, *args):
        try:
            slideTime = int(self.slideTime.get())
            if slideTime > 20:
                raise Exception
            elif slideTime < 1:
                raise Exception
            self.configData.slideTime = slideTime
        except:
            self.slideTime.set(self.configData.slideTime)


class _fileImgInfo():
    def __init__(self, filename=_NONE, uri=_NONE):
            self.filename = filename
            self.uri = uri

headers = {
    'User-Agent':'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)'
}

def getImg(imgInfo):
    global imgDiskManager
    useProxy = mNowFileInfo['useProxy']
    filename = imgInfo['filename']
    if (not imgDiskManager.fileExists(filename)) or (imgDiskManager.getFileSize(filename) < 10240):
        return BAD_FILE
        try:
            request = urllib.request.Request(imgInfo['url'],headers=headers)
            if useProxy and OPEN_PROXY:
                request.set_proxy(PROXY_HOST, 'http')
        except:
            pass
        try:
            req = urllib.request.urlopen(request, timeout=40)
            data=req.read()
        except urllib.error.URLError as ex:
            print('\n', ex)
            return BAD_FILE
        req.close()

        t_uri = imgDiskManager.getCanSaveFilePath(filename)
        with open(t_uri, "wb") as f:
           f.write(data)
    t_uri = imgDiskManager.getFilePath(filename)
    try:
        pil_image = PIL.Image.open(t_uri)
    except Exception as ex:
        print(ex)
        pil_image = BAD_FILE

    return pil_image

def loadImg():
    global mNowFileInfo
    global mNowImgInfo
    global showGifTask

    t_imgPos = mNowImgInfo['imgPos']
    t_imgNum = mNowFileInfo['sumImgNum']
    t_imgInfo = mNowImgInfo['imgInfo']
    if t_imgNum:
        if manageChecked == 2:
            root.mainFrame.manageFrame.manageList.selection_clear(0, END)
            root.mainFrame.manageFrame.manageList.selection_set(t_imgPos)

        if mNowFileInfo['imgList'][t_imgPos]['filename'].endswith('gif'):
            loadGif(mNowImgInfo['imgPos'])
        elif showGifTask:
            showGifTask.finish()
            showGifTask = None
        # elif showGifTask and showGifTask.isAlive():
        #     startGif = 0
        #     while showGifTask and showGifTask.isAlive():
        #         time.sleep(0.05)

        if mConfigData.twoPageMode:
            twoPagePos = (t_imgPos + 1) % t_imgNum
            isGoodImg = loadTwoPage(t_imgPos, twoPagePos)
            if mNowImgInfo['direct'] is BACK_IMG:
                if isGoodImg:
                    mNowImgInfo['used'] = 2
                else:
                    if mNowImgInfo['step'] == 2:
                        mNowImgInfo['imgPos'] += 1
                        mNowImgInfo['imgPos'] %= t_imgNum
                    loadSinglePage(mNowImgInfo['imgPos'])
            else:
                if isGoodImg:
                    mNowImgInfo['used'] = 2
                else:
                    loadSinglePage(t_imgPos)
        else:
            loadSinglePage(t_imgPos)
        mNowImgInfo['step'] = 2

def loadGif(imgPos):
    global startGif
    global showGifTask

    imgName = mNowFileInfo['imgList'][imgPos]['filename']
    imgName = checkImgName(imgName)
    showImg = getImg(mNowFileInfo['imgList'][imgPos])
    # startGif = 0
    label['text']=""
    label2.configure(image="")
    setImgMessage(True, imgName, imgPos)
    try:
        img_w, img_h = showImg.size
    except Exception as ex:
        print(showImg)
        setImgMessage(False, imgName, imgPos)
        return
    mNowImgInfo['scrollX'] = 0
    mNowImgInfo['scrollY'] = 0
    mNowImgInfo['imgSize'] = [img_w, img_h]
    mNowImgInfo['boxSize'] = [img_w, img_h]
    mNowImgInfo['used'] = 1
    mNowImgInfo['rotate'] = 0
    mNowImgInfo['step'] = 2
    # while showGifTask and showGifTask.isAlive():
    #     startGif = 0
    #     time.sleep(0.05)
    # startGif = 1
    print("start")
    # showGifTask = threading.Thread(target=showGif, args=(showImg, ))
    if showGifTask:
        showGifTask.finish()
    showGifTask = gifTh(showImg)
    showGifTask.setDaemon(True)
    showGifTask.start()
    return

class gifTh(threading.Thread):
    def __init__(self, imgCache):
        threading.Thread.__init__(self)
        self.isRun = True
        self.imgCache = imgCache

    def finish(self):
        self.isRun = False

    def run(self):
        global label
        print('imgCache.info', self.imgCache.info)
        p = self.imgCache.getpalette()
        self.imgCache.seek(0)
        img_w, img_h = self.imgCache.size
        try:
            backColor = self.imgCache.info['background']
        except:
            backColor = None
        # print('background:', backColor)
        # if backColor == 53:
        #     backColor = 255
        box = (0, 0, img_w, img_h)
        background = self.imgCache.crop(box)
        backPixs = background.load()
        while self.isRun:
            # print(startGif)
            # t_background = background.crop(box)
            try:
                seq = self.imgCache.tell()
                self.imgCache.seek(seq + 1)
            except EOFError:
                self.imgCache.seek(0)
                background = self.imgCache.crop(box)
                backPixs = background.load()
            # backColor = self.imgCache.info['background']

            # img = self.imgCache.convert('P', palette=p)
            if backColor:
                pixs = self.imgCache.load()
                for i in range(img_w):
                    for j in range(img_h):
                        if pixs[i, j] != 255:
                            backPixs[i, j] = pixs[i, j]
            else:
                background = self.imgCache

            # background.paste(img, box)
            # print(self.imgCache.info['duration'])
            try:
                duration = min(self.imgCache.info['duration'] / 1000.0, 1)
                # print('duration: ', duration)
            except:
                duration = 0.1
            # duration = 0.1
            tk_img = PIL.ImageTk.PhotoImage(background)
            label.configure(image=tk_img)
            label.image = tk_img
            time.sleep(duration)
            # print("1111")
        print("stop")

def loadSinglePage(imgPos):
    global label
    global mNowFileInfo
    global mNowImgInfo
    imgName = mNowFileInfo['imgList'][imgPos]['filename']
    global isShowManageList
    if isShowManageList:
        win_w = root.winfo_width() - MANAGE_BAR_BUTTON_WIDTH - MANAGE_BAR_LIST_WIDTH
    else:
        win_w = root.winfo_width() - MANAGE_BAR_BUTTON_WIDTH
    win_h = root.winfo_height() - MESSAGE_BAR_HEIGHT
    if win_h == 1:
        win_w = 800
        win_h = 600
    t_showImg = getImg(mNowFileInfo['imgList'][imgPos])
    if mNowImgInfo['rotate']:
        t_showImg = t_showImg.rotate(mNowImgInfo['rotate'])
    reSize = getFitBoxSize(t_showImg, win_w, win_h, mConfigData.scaleFitMode)
    if not reSize:
        setImgMessage(False, imgName, imgPos)
        return False
    show_img_resize = resizePic(reSize[0], reSize[1], reSize[2], reSize[3], t_showImg)

    try:
        tk_img = PIL.ImageTk.PhotoImage(show_img_resize)
    except Exception as ex:
        print(ex)
        setImgMessage(False, imgName, imgPos)
        return False

    label['text']=""
    label.configure(image=tk_img)
    label.image = tk_img
    label2.configure(image="")
    setImgPlace(0, 0)
    setImgMessage(True, imgName, imgPos)
    if mConfigData.scaleFitMode == SCALE_FIT_MODE_WIDTH and win_h < reSize[3]:
        scroll = (reSize[3] - win_h) / 2
        setImgPlace(0, scroll)
        mNowImgInfo['scrollX'] = 0
        mNowImgInfo['scrollY'] = scroll
    else:
        mNowImgInfo['scrollX'] = 0
        mNowImgInfo['scrollY'] = 0
    mNowImgInfo['imgSize'] = [reSize[0], reSize[1]]
    mNowImgInfo['boxSize'] = [reSize[2], reSize[3]]
    mNowImgInfo['used'] = 1
    mNowImgInfo['rotate'] = 0
    return True

def loadTwoPage(imgPos_a, imgPos_b):
    if imgPos_a == BAD_FILE or imgPos_b == BAD_FILE:
        return False
    imgName_a = mNowFileInfo['imgList'][imgPos_a]['filename']
    imgName_b = mNowFileInfo['imgList'][imgPos_b]['filename']
    global isShowManageList
    if isShowManageList:
        win_w = root.winfo_width() - MANAGE_BAR_BUTTON_WIDTH - MANAGE_BAR_LIST_WIDTH
    else:
        win_w = root.winfo_width() - MANAGE_BAR_BUTTON_WIDTH
    win_h = root.winfo_height() - MESSAGE_BAR_HEIGHT
    if win_h == 1:
        win_w = 800
        win_h = 600

    t_showImg_a = getImg(mNowFileInfo['imgList'][imgPos_a])
    reSize_a = getFitBoxSize(t_showImg_a, win_w / 2, win_h, SCALE_FIT_MODE_BOTH)
    if not reSize_a:
        return False
    if reSize_a[0] > reSize_a[1]:
        return False
    t_showImg_b = getImg(mNowFileInfo['imgList'][imgPos_b])
    reSize_b = getFitBoxSize(t_showImg_b, win_w / 2, win_h, SCALE_FIT_MODE_BOTH)
    if not reSize_b:
        return False
    if reSize_b[0] > reSize_b[1]:
        return False

    show_img_resize_a = resizePic(reSize_a[0], reSize_a[1], reSize_a[2], reSize_a[3], t_showImg_a)
    try:
        tk_img_a = PIL.ImageTk.PhotoImage(show_img_resize_a)
    except:
        return False
    show_img_resize_b = resizePic(reSize_b[0], reSize_b[1], reSize_b[2], reSize_b[3], t_showImg_b)
    try:
        tk_img_b = PIL.ImageTk.PhotoImage(show_img_resize_b)
    except:
        return False

    global mConfigData
    label['text']=""
    if mConfigData.mangaMode:
        label.configure(image=tk_img_b)
        label.image = tk_img_b
        label2.configure(image=tk_img_a)
        label2.image = tk_img_a
        setImgMessage(True, imgName_b + ' | ' + imgName_a, imgPos_a)
    else:
        label.configure(image=tk_img_a)
        label.image = tk_img_a
        label2.configure(image=tk_img_b)
        label2.image = tk_img_b
        setImgMessage(True, imgName_a + ' | ' + imgName_b, imgPos_a)
    setImgPlace(0, 0)
    return True

def checkImgName( imgName):
    t_imgName = imgName.replace("\\", "/")
    t_imgName = t_imgName.split('/')[-1]
    try:
        t_imgName = t_imgName.encode('cp437')
        t_imgName = t_imgName.decode("gbk")
    except:
        pass
    return t_imgName

def setImgMessage(isGoodImg, imgName, imgPos):
    global mNowFileInfo
    global mNowImgInfo

    if not isGoodImg:
        label.configure(image="")
        label2.configure(image="")
        label['text'] = "Bad Image"
        InfoMessage[IMG_NAME_MESSAGE].set(imgName)
        InfoMessage[IMG_NUM_MESSAGE].set('%d/%d' % (imgPos + 1, mNowFileInfo['sumImgNum']))
        InfoMessage[FILE_NUM_MESSAGE].set('%d/%d' % (mNowFileInfo['subPageIndex'] + 1, len(OPEN_FILE_LIST)))
        InfoMessage[FILE_NAME_MESSAGE].set(mNowFileInfo['subPageName'])
    else:
        setMessage(imgName,
                   '%d/%d' % (imgPos + 1, mNowFileInfo['sumImgNum']),
                   '%d/%d' % (mNowFileInfo['subPageIndex'] + 1, len(OPEN_FILE_LIST)),
                   mNowFileInfo['subPageName'])

def getFitBoxSize(showImg, box_x, box_y, mode):
    if showImg is BAD_FILE:
        return False
    img_w, img_h = showImg.size
    if mode is SCALE_FIT_MODE_BOTH:
        scale = 1.0 * box_y / img_h
        if img_w * scale > box_x:
            scale = 1.0 * box_x / img_w
    elif mode is SCALE_FIT_MODE_HEIGHT:
        scale = 1.0 * box_y / img_h
    elif mode is SCALE_FIT_MODE_WIDTH:
        scale = 1.0 * box_x / img_w

    if scale <= 1:
        box_width = img_w * scale
        box_height = img_h * scale
    else:
        box_width = img_w
        box_height = img_h
    return [img_w, img_h, box_width, box_height]

def resizePic(w, h, rw, rh, pil_image):
    if w == rw and h == rh:
        return pil_image
    global mConfigData
    f1 = 1.0 * rw / w
    f2 = 1.0 * rh / h
    factor = min([f1, f2])
    width = int(w * factor)
    height = int(h * factor)
    try:
        return pil_image.resize((width, height), mConfigData.scaleMode)
    except:
        return BAD_FILE

def setMessage(imgName, imgNum, fileNum, fileName):
    # s_width = root.winfo_width()
    # print('s_width: ', s_width)
    # maxImgNameLen = (s_width * MESSAGE_BAR_IMG_NAME_WIDTH) / 10
    # if len(imgName.encode('utf-8')) > maxImgNameLen:
    #     imgName = imgName[:int(maxImgNameLen / 3)] + '...' + imgName[-int(maxImgNameLen / 3):]
    InfoMessage[IMG_NAME_MESSAGE].set(imgName)
    InfoMessage[IMG_NUM_MESSAGE].set(imgNum)
    InfoMessage[FILE_NUM_MESSAGE].set(fileNum)
    InfoMessage[FILE_NAME_MESSAGE].set(fileName)

def rotateImg(MODE):
    mNowImgInfo['rotate'] = MODE * 90
    loadImg()

def changeFileListFrom(index=0, useListClass=USE_FILE_LIST):
    global FILE_LIST
    global OPEN_FILE_LIST
    global mFileListMode
    if useListClass is USE_FILE_LIST and mFileListMode is not USE_FILE_LIST:
        mFileListMode = USE_FILE_LIST
        OPEN_FILE_LIST = FILE_LIST
        changeFile(CHANGE_FILE, index)
    elif useListClass is USE_FAVORITE_LIST and mFileListMode is not USE_FAVORITE_LIST:
        mFileListMode = USE_FAVORITE_LIST
        OPEN_FILE_LIST = FAVORITE_LIST
        changeFile(CHANGE_FILE, index)

def enableRandomJumpImg():
    global RANDOM_JUMP_IMG
    global mRandomSlide
    RANDOM_JUMP_IMG = not RANDOM_JUMP_IMG
    mRandomSlide.set(RANDOM_JUMP_IMG)

def setTwoPageMode():
    mConfigData.twoPageMode = not mConfigData.twoPageMode
    loadImg()

def scaleFitMode(mode):
    mConfigData.scaleFitMode = mode
    loadImg()

def setMangaMode():
    mConfigData.mangaMode = not mConfigData.mangaMode
    loadImg()

def startSlide():
    global slideT
    global SLIDE_START
    if slideT.isAlive():
        slideLock.acquire()
        SLIDE_START = False
        slideLock.release()
    else:
        slideLock.acquire()
        SLIDE_START = True
        slideLock.release()
        slideT = threading.Timer(0, slide)
        global InfoVar
        InfoVar.set('播放幻灯片')
        slideT.start()

def stopSlide():
    global slideT
    global SLIDE_START
    if slideT.isAlive():
        slideLock.acquire()
        SLIDE_START = False
        slideLock.release()

def addFavorite():
    global FAVORITE_LIST
    global DATA_LIST
    t_pageKey = mNowFileInfo['pageKey']
    t_subPageIndex = mNowFileInfo['subPageIndex']
    t_subPageName = mNowFileInfo['subPageName']
    t_sumImgNum = mNowFileInfo['sumImgNum']
    t_pageKey = mNowFileInfo['pageKey']
    if t_subPageName:
        for i in FAVORITE_LIST:
            if i['key'] == t_pageKey and i['subPageName'] == t_subPageName:
                return
        FAVORITE_LIST.append(DATA_LIST[t_pageKey]['pageList'][t_subPageIndex])
        t_favorite_json = json.dumps(FAVORITE_LIST)
        with open('./favorite.json', 'w') as f:
            f.write(t_favorite_json)
        global InfoVar
        InfoVar.set('已收藏|' + t_subPageName)

def deleteFavorite():
    global FAVORITE_LIST
    global OPEN_FILE_LIST
    t_pageKey = mNowFileInfo['pageKey']
    t_subPageIndex = mNowFileInfo['subPageIndex']
    t_subPageName = mNowFileInfo['subPageName']
    t_sumImgNum = mNowFileInfo['sumImgNum']
    t_key = mNowFileInfo['key']
    if t_subPageName:
        for n, i in enumerate(FAVORITE_LIST):
            if i['key'] == t_key and i['subPageName'] == t_subPageName:
                FAVORITE_LIST.pop(n)
                t_favorite_json = json.dumps(FAVORITE_LIST)
                with open('./favorite.json', 'w') as f:
                    f.write(t_favorite_json)
                if mFileListMode is USE_FAVORITE_LIST:
                    OPEN_FILE_LIST = FAVORITE_LIST
                    changeFile(CHANGE_FILE, 0)
                if manageChecked == 3:
                    root.mainFrame.manageFrame.manageList.delete(0, END)
                    for info in FAVORITE_LIST:
                        root.mainFrame.manageFrame.manageList.insert(END, info['subPageName'])
                    root.mainFrame.manageFrame.manageList.selection_clear(0, END)
                    root.mainFrame.manageFrame.manageList.selection_set(0)
                return
            global InfoVar
            InfoVar.set('已取消收藏|' + t_subPageName)

def deletePackage():
    global mNowFileInfo
    global mNowImgInfo
    global DATA_LIST
    global OPEN_FILE_LIST
    global FILE_LIST
    global imgDiskManager

    subPageList = DATA_LIST[mNowFileInfo['pageKey']]['pageList'][mNowFileInfo['subPageIndex']]
    t_name = subPageList['subPageName']
    subPageList.update({'delete': True})
    for l in subPageList['subPageList']:
        imgList = l['imgList']
        for imgInfo in imgList:
            if imgDiskManager.fileExists(imgInfo['filename']):
                path = imgDiskManager.getFilePath(imgInfo['filename'])
                os.remove(path)
    DATA_LIST[mNowFileInfo['pageKey']]['pageList'][mNowFileInfo['subPageIndex']] = subPageList
    # del DATA_LIST[mNowFileInfo['pageKey']]['pageList'][mNowFileInfo['subPageIndex']]
    t_conf_json = json.dumps(DATA_LIST)
    with open('conf.json', 'w') as f:
        f.write(t_conf_json)
    if manageChecked == 1:
        global FILE_LIST
        root.mainFrame.manageFrame.manageList.delete(0, END)
        for info in FILE_LIST:
            try:
                d = info['delete']
            except:
                d = False
            if d:
                name = '(Delete) |' + info['subPageName']
            else:
                name = info['subPageName']
            root.mainFrame.manageFrame.manageList.insert(END, name)
        root.mainFrame.manageFrame.manageList.selection_clear(0, END)
        root.mainFrame.manageFrame.manageList.selection_set(mNowFileInfo['subPageIndex'])
    changeFile(NEXT_FILE)
    global InfoVar
    InfoVar.set('已删除|' + t_name)

class downPackTh(threading.Thread):
    def __init__(self, imgList, useProxy):
        threading.Thread.__init__(self)
        global InfoVar
        global imgDiskManager
        n = 0
        lock = threading.Lock()
        self.imgList = imgList
        self.queue = []
        # print('startDown')
        for imgInfo in imgList:
            filename = imgInfo['filename']
            if (not imgDiskManager.fileExists(filename)) or (imgDiskManager.getFileSize(filename) < 10240):
                self.queue.append(imgInfo)
            else:
                n += 1
        self.thInfo = [useProxy, n, len(imgList), lock]
        self.live = True

    def finish(self):
        self.live = False

    def downImgTh(self, imgInfo, thInfo):
        global imgDiskManager
        filename = imgInfo['filename']
        try:
            request = urllib.request.Request(imgInfo['url'],headers=headers)
            if thInfo[0] and OPEN_PROXY:
                request.set_proxy(PROXY_HOST, 'http')
        except:
            pass
        try:
            req = urllib.request.urlopen(request, timeout=10)
            data=req.read()
            req.close()
        except urllib.error.URLError as ex:
            print(ex)
            data = ''
        except Exception as ex:
            print(ex)
            data = ''
        if data:
            t_uri = imgDiskManager.getCanSaveFilePath(filename)
            print("t_uri", t_uri)
            with open(t_uri, "wb") as f:
               f.write(data)
        if self.live:
            thInfo[3].acquire()
            thInfo[1] += 1
            global InfoVar
            InfoVar.set('下载中... | %d / %d' % (thInfo[1], thInfo[2]))
            # print('下载中... | %d / %d' % (thInfo[1], thInfo[2]))
            thInfo[3].release()

    def run(self):
        global InfoVar
        global imgDiskManager
        if self.queue:
            InfoVar.set('下载中... | %d / %d' % (self.thInfo[1], len(self.imgList)))
            self.taskList = []
            while True:
                time.sleep(0.2)
                liveNum = 0
                for t in self.taskList:
                    if t and t.isAlive():
                        liveNum += 1
                if self.queue and self.live:
                    if liveNum <= 4:
                        task = self.queue.pop(0)
                        taskTh = threading.Thread(target=self.downImgTh, args=(task, self.thInfo))
                        taskTh.setDaemon(True)
                        taskTh.start()
                        self.taskList.append(taskTh)
                elif liveNum == 0:
                    break
            if self.live:
                InfoVar.set('下载完成')
                # imgDiskManager.refresh()
                print('Img Down Over ^_^')
                loadImg()
        else:
            InfoVar.set('下载完成')

def downPackage():
    global mNowFileInfo
    global downPackTask
    imgList = mNowFileInfo['imgList']
    useProxy = mNowFileInfo['useProxy']
    if downPackTask:
        downPackTask.finish()
    downPackTask = downPackTh(imgList, useProxy)
    downPackTask.setDaemon(True)
    downPackTask.start()

def initMenu(master):
    global mTwoViewMode
    global mConfigData
    master.menu = Menu(master)

    master.menu.filemenu = Menu(master)
    master.menu.add_cascade(label='文件', menu=master.menu.filemenu)
    master.menu.filemenu.add_command(label="首选项...", command=config)
    master.menu.filemenu.add_separator()
    master.menu.filemenu.add_command(label="退出", command=closeWin)

    master.menu.viewmenu = Menu(master)
    master.menu.add_cascade(label='查看', menu=master.menu.viewmenu)
    global mTwoViewMode
    mTwoViewMode = IntVar()
    mTwoViewMode.set(mConfigData.twoPageMode)
    master.menu.viewmenu.add_checkbutton(variable=mTwoViewMode, label="双页模式",command=setTwoPageMode)
    global mMangaMode
    mMangaMode = IntVar()
    mMangaMode.set(mConfigData.mangaMode)
    master.menu.viewmenu.add_checkbutton(variable=mMangaMode, label="漫画模式",command=setMangaMode)
    master.menu.viewmenu.add_separator()
    global mViewMode
    mViewMode = IntVar()
    mViewMode.set(mConfigData.scaleFitMode)
    master.menu.viewmenu.add_radiobutton(variable=mViewMode, value=0, label="最佳适应模式", command=lambda: scaleFitMode(0))
    master.menu.viewmenu.add_radiobutton(variable=mViewMode, value=1, label="适应宽度模式", command=lambda: scaleFitMode(1))
    master.menu.viewmenu.add_radiobutton(variable=mViewMode, value=2, label="适应高度模式", command=lambda: scaleFitMode(2))
    master.menu.viewmenu.add_separator()
    global rotateModeVar
    rotateModeVar = IntVar()
    rotateModeVar.set(0)
    master.menu.viewmenu.add_radiobutton(variable=rotateModeVar, value=0, label="正常角度", command=lambda: rotateImg(0))
    master.menu.viewmenu.add_radiobutton(variable=rotateModeVar, value=3, label="顺时针旋转 90度", command=lambda: rotateImg(3))
    master.menu.viewmenu.add_radiobutton(variable=rotateModeVar, value=1, label="逆时针旋转 90度", command=lambda: rotateImg(1))
    master.menu.viewmenu.add_radiobutton(variable=rotateModeVar, value=2, label="旋转 180度", command=lambda: rotateImg(2))

    master.menu.jumpmenu = Menu(master)
    master.menu.add_cascade(label='跳转', menu=master.menu.jumpmenu)
    master.menu.jumpmenu.add_command(label="文件跳转...", command=fileJump)
    master.menu.jumpmenu.add_command(label="文件随机跳转", command=fileRandomJump)
    master.menu.jumpmenu.add_separator()
    master.menu.jumpmenu.add_command(label="图片跳转...", command=imgJump)
    # master.menu.jumpmenu.add_command(label="图片随机跳转", command=fileDialog)
    master.menu.jumpmenu.add_separator()
    master.menu.jumpmenu.add_command(label="下一页", command=lambda: changePicSingle(NEXT_IMG))
    master.menu.jumpmenu.add_command(label="上一页", command=lambda: changePicSingle(BACK_IMG))
    master.menu.jumpmenu.add_command(label="下一文件包", command=lambda: changeFile(NEXT_FILE))
    master.menu.jumpmenu.add_command(label="上一文件包", command=lambda: changeFile(BACK_FILE))
    master.menu.jumpmenu.add_separator()
    global mSlide
    mSlide = IntVar()
    mSlide.set(0)
    master.menu.jumpmenu.add_checkbutton(variable=mSlide, label="放映幻灯片", command=startSlide)
    global mRandomSlide
    mRandomSlide = IntVar()
    mRandomSlide.set(RANDOM_JUMP_IMG)
    master.menu.jumpmenu.add_checkbutton(variable=mRandomSlide, label="随机模式", command=enableRandomJumpImg)

    master['menu'] = master.menu

def initMouseRightMenu(master):
    global rightMenu
    rightMenu = Menu(master)

    rightMenu.add_command(label="收藏", command=addFavorite)
    rightMenu.add_command(label="删除包", command=deletePackage)
    rightMenu.add_command(label="下载包", command=downPackage)
    rightMenu.add_command(label="下一页", command=lambda: changePicSingle(NEXT_IMG))
    rightMenu.add_command(label="上一页", command=lambda: changePicSingle(BACK_IMG))
    rightMenu.add_separator()
    global mTwoViewMode
    rightMenu.add_checkbutton(variable=mTwoViewMode, label="双页模式", command=setTwoPageMode)
    global mMangaMode
    rightMenu.add_checkbutton(variable=mMangaMode, label="漫画模式",command=setMangaMode)
    global mRandomSlide
    rightMenu.add_checkbutton(variable=mRandomSlide, label="随机模式", command=enableRandomJumpImg)
    rightMenu.add_separator()
    rightMenu.add_command(label="文件随机跳转", command=fileRandomJump)
    rightMenu.add_command(label="图片跳转...", command=imgJump)

def initMessage(master):
    global InfoMessage

    master.messageLabel = Label(master, bg='white')
    master.messageLabel.place(relx=0, rely=1, height=MESSAGE_BAR_HEIGHT, relwidth=1, anchor=SW)
    global InfoVar
    InfoVar = StringVar()
    master.messageLabel.infoImgNameMessage = tkinter.Message(master.messageLabel, aspect=4000, textvariable=InfoVar, justify=LEFT)
    master.messageLabel.infoImgNameMessage.place(in_=master.messageLabel,
                                                 relx=0, rely=0,
                                                 relheight=1,
                                                 relwidth=MESSAGE_BAR_INFO_WIDTH - 0.001,
                                                 anchor=NW)
    ImgNameVar = StringVar()
    master.messageLabel.infoImgNameMessage = tkinter.Message(master.messageLabel, aspect=4000, textvariable=ImgNameVar, justify=LEFT)
    master.messageLabel.infoImgNameMessage.place(in_=master.messageLabel,
                                                 relx=MESSAGE_BAR_INFO_WIDTH, rely=0,
                                                 relheight=1,
                                                 relwidth=MESSAGE_BAR_IMG_NAME_WIDTH - 0.001,
                                                 anchor=NW)
    # master.messageLabel.infoImgNameMessage.pack(side=LEFT)
    ImgNumVar = StringVar()
    master.messageLabel.infoImgNumMessage = tkinter.Message(master.messageLabel, aspect=500, textvariable=ImgNumVar, justify=RIGHT)
    master.messageLabel.infoImgNumMessage.place(in_=master.messageLabel,
                                                relx=0.5, rely=0,
                                                relheight=1,
                                                relwidth=MESSAGE_BAR_IMG_NUM_WIDTH - 0.001,
                                                anchor=NW)
    FileNumVar = StringVar()
    master.messageLabel.infoFileNumMessage = tkinter.Message(master.messageLabel, aspect=500, textvariable=FileNumVar, justify=RIGHT)
    master.messageLabel.infoFileNumMessage.place(in_=master.messageLabel,
                                                 relx=0.6, rely=0,
                                                 relheight=1,
                                                 relwidth=MESSAGE_BAR_FILE_NUM_WIDTH - 0.001,
                                                 anchor=NW)
    FileNameVar = StringVar()
    master.messageLabel.infoFileNameMessage = tkinter.Message(master.messageLabel, aspect=4000, textvariable=FileNameVar, justify=RIGHT)
    master.messageLabel.infoFileNameMessage.place(in_=master.messageLabel,
                                                  relx=0.7, rely=0,
                                                  relheight=1,
                                                  relwidth=MESSAGE_BAR_FILE_NAME_WIDTH - 0.001,
                                                  anchor=NW)
    InfoVar.set('准备就绪')
    ImgNameVar.set('OK')
    ImgNumVar.set('OK')
    FileNumVar.set('OK')
    FileNameVar.set('OK')
    InfoMessage = [ImgNameVar, ImgNumVar, FileNumVar, FileNameVar]

def config():
    global mConfigData
    configDialog(root, command=setConfig, oldConfig=mConfigData)

def setConfig(data):
    if data:
        global mConfigData
        mConfigData.background = data.background
        label['fg'] = getInverse(mConfigData.background)
        label2['fg'] = getInverse(mConfigData.background)
        mConfigData.customBackground = data.customBackground
        mConfigData.restore = data.restore
        mConfigData.slideTime = data.slideTime
        mConfigData.scaleMode = data.scaleMode
        saveConfigToFile(mConfigData)

        root.mainFrame['bg'] = mConfigData.background
        root.mainFrame.imgFrame['bg'] = mConfigData.background
        label['bg'] = mConfigData.background
        label2['bg'] = mConfigData.background

def getConfigFromFile():
    t_config = _configData()
    try:
        with open('./configBrowser.json', 'r') as f:
            confJson = f.read()
        CONF_JSON = json.JSONDecoder().decode(confJson)
        t_config.setDataFromDict(CONF_JSON)
    except:
        t_conf_json = json.dumps(t_config.getDataDict())
        with open('./configBrowser.json', 'w') as f:
            f.write(t_conf_json)
    return t_config

def saveConfigToFile(config_data):
    t_conf_json = json.dumps(config_data.getDataDict())
    with open('./configBrowser.json', 'w') as f:
        f.write(t_conf_json)

def slide():
    # print ("slide")
    global slideLock
    global mConfigData
    while(True):
        slideLock.acquire()
        checkTmp = SLIDE_START
        slideLock.release()
        if checkTmp:
            ShowPic(NEXT_IMG)
            time.sleep(mConfigData.slideTime)
        else:
            break
    global InfoVar
    InfoVar.set('已停止幻灯片')

def ShowPic(value, jump_num=0):
    global mNowImgInfo
    global mNowFileInfo
    global mConfigData
    global RANDOM_LIST
    global RANDOM_LIST_INDEX
    global RANDOM_LIST_LENGTH
    global rotateModeVar

    if value is JUMP_IMG:
        mNowImgInfo['imgPos'] = jump_num
    else:
        if value is BACK_IMG:
            if mConfigData.twoPageMode:
                step = -2
            else:
                step = -1
        elif value is NEXT_IMG:
            step = mNowImgInfo['used']

        if RANDOM_JUMP_IMG:
            RANDOM_LIST_INDEX += step
            RANDOM_LIST_INDEX %= RANDOM_LIST_LENGTH
            mNowImgInfo['imgPos'] = RANDOM_LIST[RANDOM_LIST_INDEX]
        else:
            mNowImgInfo['imgPos'] += step
            if mNowImgInfo['imgPos'] > mNowFileInfo['sumImgNum'] - 1:
                changeFile(NEXT_FILE)
            elif mNowImgInfo['imgPos'] < 0:
                if mConfigData.twoPageMode:
                    changeFile(BACK_FILE, imgPos=-2)
                else:
                    changeFile(BACK_FILE, imgPos=-1)
    mNowImgInfo['imgPos'] %= mNowFileInfo['sumImgNum']
    mNowImgInfo['direct'] = value
    loadImg()
    rotateModeVar.set(0)

def changePicSingle(value):
    global mNowImgInfo
    global rotateModeVar
    mNowImgInfo['step'] = 1
    if value is BACK_IMG:
        mNowImgInfo['imgPos'] -= 1
    elif value is NEXT_IMG:
        mNowImgInfo['imgPos'] += 1
    mNowImgInfo['direct'] = value
    loadImg()
    rotateModeVar.set(0)

def changeFile(direct, jump_file=0, imgPos=0):
    global label
    global label2
    global mNowFileInfo
    global mNowImgInfo
    global downPackTimer

    label.configure(image="")
    label2.configure(image="")
    label['text'] = "Loading"
    subPageIndex = mNowFileInfo['subPageIndex']
    isDelete = True
    while isDelete:
        if direct is JUMP_FILE or direct is CHANGE_FILE:
            direct = NEXT_FILE
            subPageIndex = jump_file
        elif direct is NEXT_FILE:
            subPageIndex = (subPageIndex + 1) % len(OPEN_FILE_LIST)
        elif direct is BACK_FILE:
            subPageIndex = (subPageIndex - 1) % len(OPEN_FILE_LIST)
        try:
            isDelete = OPEN_FILE_LIST[subPageIndex]['delete']
        except:
            isDelete = False
    mNowFileInfo['subPageName'] = OPEN_FILE_LIST[subPageIndex]['subPageName']
    mNowFileInfo['key'] = OPEN_FILE_LIST[subPageIndex]['key']
    mNowFileInfo['subPageIndex'] = subPageIndex
    t_subPageList = OPEN_FILE_LIST[subPageIndex]['subPageList']
    mNowFileInfo['imgList'] = []

    for n, t in enumerate(t_subPageList):
        try:
            t['imgList']
        except:
            DATA_LIST[mNowFileInfo['pageKey']]['pageList'][mNowFileInfo['subPageIndex']]['subPageList'].pop(n)
            t_conf_json = json.dumps(DATA_LIST)
            with open('conf.json', 'w') as f:
                f.write(t_conf_json)
    n = 0
    for t in t_subPageList:
        mNowFileInfo['imgList'] += t['imgList']
        n += len(t['imgList'])
    mNowFileInfo['sumImgNum'] = n

    imgList = []
    if mNowFileInfo['imgList']:
        imgPos %= len(mNowFileInfo['imgList'])
        imgInfo = mNowFileInfo['imgList'][imgPos]

        mNowImgInfo = {'imgPos': imgPos,
                       'used': 1,
                       'direct': NEXT_IMG,
                       'rotate': 0,
                       'step': 1,
                       'imgInfo': imgInfo,
                       'scrollX': 0,
                       'scrollY': 0,
                       'imgSize': [0, 0],
                       'boxSize': [0, 0]}
    if manageChecked == 1:
        root.mainFrame.manageFrame.manageList.selection_clear(0, END)
        root.mainFrame.manageFrame.manageList.selection_set(subPageIndex)
    loadImg()
    if downPackTimer:
        downPackTimer.cancel()
    downPackTimer = threading.Timer(3, downPackage)
    downPackTimer.start()

def manageButtonEvent(index):
    global manageButtonList
    global manageChecked
    global isShowManageList
    global root
    for i, b in enumerate(manageButtonList):
        if i == index and manageChecked != index:
            b['bg'] = '#F1F1F1'
        else:
            b['bg'] = '#D3D3D3'
    if manageChecked == index:
        isShowManageList = False
        manageChecked = -1
        showManageList(False)
        loadImg()
        return
    if not isShowManageList:
        isShowManageList = True
        showManageList(True)
        loadImg()
    manageChecked = index
    if index == 0:
        global KEY_LIST
        root.mainFrame.manageFrame.manageList.delete(0, END)
        for info in KEY_LIST:
            root.mainFrame.manageFrame.manageList.insert(END, info)
        root.mainFrame.manageFrame.manageList.selection_clear(0, END)
        if mNowFileInfo['pageKey']:
            root.mainFrame.manageFrame.manageList.selection_set(KEY_LIST.index(mNowFileInfo['pageKey']))
    elif index == 1:
        global FILE_LIST
        root.mainFrame.manageFrame.manageList.delete(0, END)
        for info in FILE_LIST:
            try:
                d = info['delete']
            except:
                d = False
            if d:
                name = '(Delete) |' + info['subPageName']
            else:
                name = info['subPageName']
            root.mainFrame.manageFrame.manageList.insert(END, name)
        root.mainFrame.manageFrame.manageList.selection_clear(0, END)
        root.mainFrame.manageFrame.manageList.selection_set(mNowFileInfo['subPageIndex'])
    elif index == 2:
        root.mainFrame.manageFrame.manageList.delete(0, END)
        for info in mNowFileInfo['imgList']:
            root.mainFrame.manageFrame.manageList.insert(END, info['filename'])
        root.mainFrame.manageFrame.manageList.selection_clear(0, END)
        root.mainFrame.manageFrame.manageList.selection_set(mNowImgInfo['imgPos'])
    elif index == 3:
        global FAVORITE_LIST
        root.mainFrame.manageFrame.manageList.delete(0, END)
        for info in FAVORITE_LIST:
            root.mainFrame.manageFrame.manageList.insert(END, info['subPageName'])

def showManageList(show):
    global root
    if show:
        root.mainFrame.manageFrame.place(width=MANAGE_BAR_BUTTON_WIDTH + MANAGE_BAR_LIST_WIDTH)
    else:
        root.mainFrame.manageFrame.place(width=MANAGE_BAR_BUTTON_WIDTH)

def checkPosInManage(event):
    global isShowManageList
    if isShowManageList:
        managePos = MANAGE_BAR_BUTTON_WIDTH + MANAGE_BAR_LIST_WIDTH
    else:
        managePos = MANAGE_BAR_BUTTON_WIDTH
    t = root.winfo_geometry()
    win_w = int(t.split('+')[-2])
    ev_x = event.x_root - win_w
    if ev_x < managePos:
        return True
    return False

def mouseRightEvent(event):
    global rightMenu
    if checkPosInManage(event):
        return
    # global RIGHT_MENU_VISIBLE
    if mFileListMode is USE_FILE_LIST:
        rightMenu.delete(1)
        rightMenu.insert_command(0, label="收藏", command=addFavorite)
    elif mFileListMode is USE_FAVORITE_LIST:
        rightMenu.delete(1)
        rightMenu.insert_command(0, label="取消收藏", command=deleteFavorite)
    rightMenu.unpost()
    rightMenu.post(event.x_root, event.y_root)
    # RIGHT_MENU_VISIBLE = True

def mouseEvent(event):
    global nTime
    nTime = time.time()
    global slideT
    global SLIDE_START
    global rightMenu
    # global RIGHT_MENU_VISIBLE
    rightMenu.unpost()

    if checkPosInManage(event):
        return
    # if RIGHT_MENU_VISIBLE:
    #     rightMenu.unpost()
    #     RIGHT_MENU_VISIBLE = False
    #     return

    s_width = root.winfo_width()
    s_height = root.winfo_height()
    t=root.winfo_geometry()
    win_w = int(t.split('+')[-2])
    win_h = int(t.split('+')[-1])
    ev_x = event.x_root - win_w
    ev_y = event.y_root - win_h

    if ev_x > s_width / 3.0 * 2.0:
        ShowPic(NEXT_IMG)
    elif ev_x < s_width / 3.0:
        ShowPic(BACK_IMG)
    elif ev_y > s_height / 3.0 * 2.0:
        changeFile(NEXT_FILE)
    elif ev_y < s_height / 3.0:
        changeFile(BACK_FILE)
    else:
        startSlide()

def mouseWheelEvent(event):
    global mNowImgInfo
    global mConfigData
    global root
    if checkPosInManage(event):
        return

    if not (mConfigData.twoPageMode or mConfigData.scaleFitMode is SCALE_FIT_MODE_BOTH):
        img_w, img_h = mNowImgInfo['boxSize']
        box_w = root.winfo_width()
        box_h = root.winfo_height() - MESSAGE_BAR_HEIGHT
        t_scroll_x = mNowImgInfo['scrollX']
        t_scroll_y = mNowImgInfo['scrollY']
        if mConfigData.scaleFitMode is SCALE_FIT_MODE_WIDTH:
            max_scroll = (img_h - box_h) / 2
            if max_scroll < 0:
                return
            if event.num == 4:
                t_scroll_y = min([t_scroll_y + 20, max_scroll])
            elif event.num == 5:
                t_scroll_y = max(t_scroll_y - 20, -max_scroll)
        elif mConfigData.scaleFitMode is SCALE_FIT_MODE_HEIGHT:
            max_scroll = (img_w - box_w) / 2
            if max_scroll < 0:
                return
            if event.num == 4:
                t_scroll_x = min(t_scroll_x + 20, max_scroll)
            elif event.num == 5:
                t_scroll_x = max(t_scroll_x - 20, -max_scroll)
        setImgPlace(t_scroll_x, t_scroll_y)
        mNowImgInfo['scrollX'] = t_scroll_x
        mNowImgInfo['scrollY'] = t_scroll_y

def setImgPlace(mX, mY):
    global root
    global isShowManageList
    if isShowManageList:
        root.mainFrame.imgFrame.place(x=mX + (MANAGE_BAR_BUTTON_WIDTH + MANAGE_BAR_LIST_WIDTH) / 2, y=mY - MESSAGE_BAR_HEIGHT / 2)
    else:
        root.mainFrame.imgFrame.place(x=mX + MANAGE_BAR_BUTTON_WIDTH / 2, y=mY - MESSAGE_BAR_HEIGHT / 2)

def fileJump():
    jump_num = askstring(title='文件跳转', prompt="请输入跳转到的文件序号: ")
    try:
        jump_num = int(jump_num)
        jump_num = max([1, jump_num])
        jump_num = min([len(OPEN_FILE_LIST), jump_num])
        changeFile(JUMP_FILE, jump_file=jump_num - 1)
    except:
        showerror(title="错误", message="输入错误！")

def imgJump():
    jump_num = askstring(title='图片跳转', prompt="请输入跳转到的图片序号: ")
    try:
        jump_num = int(jump_num)
        jump_num = max([1, jump_num])
        ShowPic(JUMP_IMG, jump_num=jump_num - 1)
    except:
        print("输入错误")

def fileRandomJump():
    if askquestion(title="随机跳转", message="是否随机跳转到一个压缩包?") == YES:
        jump_num = random.randint(0, len(OPEN_FILE_LIST))
        changeFile(JUMP_FILE, jump_file=jump_num)

def onKeyPress(ev):
    global nTime
    nTime = time.time()
    global slideT
    global SLIDE_START
    # print(ev.keycode)
    if ev.keycode == KEY_CODE.codeS:
        startSlide()
        return
    stopSlide()

    if ev.keycode == KEY_CODE.codeLeft:
        ShowPic(BACK_IMG)
    elif ev.keycode == KEY_CODE.codeRight:
        ShowPic(NEXT_IMG)
    elif ev.keycode == KEY_CODE.codeD or ev.keycode == KEY_CODE.codeDown:
        changeFile(NEXT_FILE)
    elif ev.keycode == KEY_CODE.codeA or ev.keycode == KEY_CODE.codeUp:
        changeFile(BACK_FILE)
    elif ev.keycode == KEY_CODE.codeW:
        fileJump()
    elif ev.keycode == KEY_CODE.codeE:
        imgJump()
    elif ev.keycode == KEY_CODE.codeC:
        fileRandomJump()
    elif ev.keycode == KEY_CODE.codeM:
        deletePackage()
    elif ev.keycode == KEY_CODE.codeN:
        addFavorite()
    elif ev.keycode == KEY_CODE.codeB:
        downPackage()

def closeWin():
    global mConfigData

    if mConfigData.restore:
        mConfigData.restoreData['pageKey'] = mNowFileInfo['pageKey']
        mConfigData.restoreData['subPageIndex'] = mNowFileInfo['subPageIndex']
        mConfigData.restoreData['subPageName'] = mNowFileInfo['subPageName']
        mConfigData.restoreData['imgPos'] = mNowImgInfo['imgPos']

    saveConfigToFile(mConfigData)
    root.destroy()

def selectManageList(event):
    global mFileListMode
    if manageChecked == 0:
        global FILE_LIST
        global OPEN_FILE_LIST
        global mNowFileInfo
        key = KEY_LIST[root.mainFrame.manageFrame.manageList.curselection()[0]]
        mNowFileInfo['pageKey'] = key
        mNowFileInfo['useProxy'] = DATA_LIST[key]['useProxy']
        mFileListMode = USE_FILE_LIST
        FILE_LIST = DATA_LIST[key]['pageList']
        OPEN_FILE_LIST = FILE_LIST
        changeFile(CHANGE_FILE, 0)
    elif manageChecked == 1:
        if mFileListMode == USE_FILE_LIST:
            changeFile(JUMP_FILE, root.mainFrame.manageFrame.manageList.curselection()[0])
        else:
            changeFileListFrom(root.mainFrame.manageFrame.manageList.curselection()[0], USE_FILE_LIST)
    elif manageChecked == 2:
        ShowPic(JUMP_IMG, root.mainFrame.manageFrame.manageList.curselection()[0])
    elif manageChecked == 3:
        if mFileListMode == USE_FAVORITE_LIST:
            changeFile(JUMP_FILE, root.mainFrame.manageFrame.manageList.curselection()[0])
        else:
            changeFileListFrom(root.mainFrame.manageFrame.manageList.curselection()[0], USE_FAVORITE_LIST)

def getInverse(color):
    R_color_str = color[1:3]
    G_color_str = color[3:5]
    B_color_str = color[5:7]
    R_color_int = 255 - int(R_color_str, 16)
    G_color_int = 255 - int(G_color_str, 16)
    B_color_int = 255 - int(B_color_str, 16)
    R_color_inverse_str = hex(R_color_int)[-2:]
    G_color_inverse_str = hex(G_color_int)[-2:]
    B_color_inverse_str = hex(B_color_int)[-2:]
    return '#' + R_color_inverse_str + G_color_inverse_str + B_color_inverse_str

'''入口'''
if __name__ == '__main__':
    KEY_CODE = _KeyCode()
    mConfigData = getConfigFromFile()
    mFileListMode = USE_FILE_LIST
    downPackTask = None
    downPackTimer = None
    imgDiskManager = ImgDiskManager.ImgDiskManager()
    startGif = 0
    showGifTask = None

    root = tk.Tk()
    root.geometry("900x600+%d+%d" % ((800 - root.winfo_width()) / 2, (600 - root.winfo_height()) / 2))
    root.protocol('WM_DELETE_WINDOW', closeWin)
    # TODO
    # root.wm_attributes('-zoomed',1)
    root.wm_attributes('-topmost', 0)
    root.bind("<Button-1>", mouseEvent)
    root.bind("<Button-3>", mouseRightEvent)
    root.bind("<Button-4>", mouseWheelEvent)
    root.bind("<Button-5>", mouseWheelEvent)
    # root.bind('<Configure>', screenSizeChange)
    root.bind("<Key>", onKeyPress)
    root.title('图包浏览器')
    initMenu(root)
    root.mainFrame = Frame(root, bg=mConfigData.background)
    root.mainFrame.pack(fill=BOTH, expand=1)
    # label = tk.Label(root, image=_NONE, width=600, height=550, font='Helvetica -18 bold', bg='red')
    root.mainFrame.manageFrame = Frame(root)
    root.mainFrame.manageFrame.fileButton = Button(root.mainFrame.manageFrame,
                                                   text='网\n站',
                                                   relief=FLAT,
                                                   width=1,
                                                   bg='#D3D3D3',
                                                   command=lambda: manageButtonEvent(0))
    root.mainFrame.manageFrame.fileButton.place(x=0, y=0, width=20, height=70)
    root.mainFrame.manageFrame.picButton = Button(root.mainFrame.manageFrame,
                                                  text='子\n页',
                                                  relief=FLAT,
                                                  width=1,
                                                  bg='#D3D3D3',
                                                  command=lambda: manageButtonEvent(1))
    root.mainFrame.manageFrame.picButton.place(x=0, y=70, width=20, height=70)
    root.mainFrame.manageFrame.favoriteButton = Button(root.mainFrame.manageFrame,
                                                       text='图\n片',
                                                       relief=FLAT,
                                                       width=1,
                                                       bg='#D3D3D3',
                                                       command=lambda: manageButtonEvent(2))
    root.mainFrame.manageFrame.favoriteButton.place(x=0, y=140, width=20, height=70)
    root.mainFrame.manageFrame.bookmarkButton = Button(root.mainFrame.manageFrame,
                                                       text='收\n藏\n夹',
                                                       relief=FLAT,
                                                       width=1,
                                                       bg='#D3D3D3',
                                                       command=lambda: manageButtonEvent(3))
    root.mainFrame.manageFrame.bookmarkButton.place(x=0, y=210, width=20, height=70)
    root.mainFrame.manageFrame.place(x=0, y=0, width=MANAGE_BAR_BUTTON_WIDTH + MANAGE_BAR_LIST_WIDTH, relheight=1, height=-MESSAGE_BAR_HEIGHT, anchor=NW)
    manageChecked = -1
    isShowManageList = False
    manageButtonList = [root.mainFrame.manageFrame.fileButton,
                        root.mainFrame.manageFrame.picButton,
                        root.mainFrame.manageFrame.favoriteButton,
                        root.mainFrame.manageFrame.bookmarkButton]

    refreshManageBar = False
    manageListVar = StringVar()
    root.mainFrame.manageFrame.manageList = Listbox(root.mainFrame.manageFrame, selectmode=SINGLE, listvariable=manageListVar, selectbackground='#FF7F50')
    root.mainFrame.manageFrame.listScrollBar = Scrollbar(root.mainFrame.manageFrame)
    root.mainFrame.manageFrame.listScrollHorizontalBar = Scrollbar(root.mainFrame.manageFrame, orient=HORIZONTAL)
    root.mainFrame.manageFrame.manageList.bind('<ButtonRelease-1>', selectManageList)
    showManageList(False)
    root.mainFrame.manageFrame.manageList.place(x=MANAGE_BAR_BUTTON_WIDTH, y=0, width=MANAGE_BAR_LIST_WIDTH - 10, relheight=1, height=-10, anchor=NW)
    root.mainFrame.manageFrame.listScrollBar.place(x=MANAGE_BAR_BUTTON_WIDTH + MANAGE_BAR_LIST_WIDTH - 10, y=0, width=10, relheight=1, height=-10, anchor=NW)
    root.mainFrame.manageFrame.listScrollHorizontalBar.place(x=MANAGE_BAR_BUTTON_WIDTH, rely=1, width=MANAGE_BAR_LIST_WIDTH, height=10, anchor=SW)
    root.mainFrame.manageFrame.manageList['yscrollcommand'] = root.mainFrame.manageFrame.listScrollBar.set
    root.mainFrame.manageFrame.listScrollBar['command'] = root.mainFrame.manageFrame.manageList.yview
    root.mainFrame.manageFrame.manageList['xscrollcommand'] = root.mainFrame.manageFrame.listScrollHorizontalBar.set
    root.mainFrame.manageFrame.listScrollHorizontalBar['command'] = root.mainFrame.manageFrame.manageList.xview

    root.mainFrame.imgFrame = Frame(root.mainFrame, bg=mConfigData.background)
    root.mainFrame.imgFrame.place(relx=0.5, rely=0.5, y=-MESSAGE_BAR_HEIGHT / 2, x=MANAGE_BAR_BUTTON_WIDTH / 2, anchor=CENTER)
    label = tk.Label(root.mainFrame.imgFrame, image=_NONE, font='Helvetica -18 bold', fg=getInverse(mConfigData.background), bg=mConfigData.background)
    label.grid()
    label2 = tk.Label(root.mainFrame.imgFrame, image=_NONE, font='Helvetica -18 bold', fg=getInverse(mConfigData.background), bg=mConfigData.background)
    label2.grid(row=0, column=1)
    # label2.grid_forget()
    # label.pack(padx=15, pady=15, expand=1, fill=BOTH)
    initMessage(root.mainFrame)
    initMouseRightMenu(root)

    mNowImgInfo = {'imgPos': 0,
                   'used': 1,
                   'direct': NEXT_IMG,
                   'rotate': 0,
                   'step': 1,
                   'imgInfo': {'filename': '',
                               'url': ''},
                   'scrollX': 0,
                   'scrollY': 0,
                   'imgSize': [0, 0],
                   'boxSize': [0, 0]}
    FILE_LIST = []
    OPEN_FILE_LIST = []
    mNowFileInfo = {'pageKey': '',
                    'key': '',
                    'useProxy': False,
                    'subPageIndex': 0,
                    'subPageName': '',
                    'imgList': [],
                    'sumImgNum': 0}

    slideLock = threading.Lock()
    SLIDE_START = False
    slideT = threading.Thread(target=slide)
    # if mConfigData.restore and mConfigData.restoreData['filename']:
    #     t_page_key = mConfigData.restoreData['pageKey']
    #     t_sub_page_index = mConfigData.restoreData['subPageIndex']
    #

    try:
        with open('./favorite.json', 'r') as f:
            favoriteJson = f.read()
    except:
        with open('./favorite.json', 'w') as f:
            f.write('')
        favoriteJson = ''
    try:
        FAVORITE_LIST = json.JSONDecoder().decode(favoriteJson)
    except:
        FAVORITE_LIST = []

    try:
        with open('./conf.json', 'r') as f:
            dataJson = f.read()
    except:
        with open('./conf.json', 'w') as f:
            f.write('')
        dataJson = ''
    try:
        DATA_LIST = json.JSONDecoder().decode(dataJson)
    except:
        DATA_LIST = {}
    if not os.path.exists("./downImg/"):
        os.mkdir("./downImg/")

    KEY_LIST = []
    for k, page in DATA_LIST.items():
        KEY_LIST.append(k)
    KEY_LIST.sort()
    root.mainloop()
